package com.oauth2_security.handle;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.oauth2_security.entity.UserInfo;
import com.oauth2_security.enums.SystemRest;
import com.oauth2_security.exception.RequestAuthorizationException;
import com.oauth2_security.model.RestFulVO;
//import com.ucarbbs.adminweb.dto.MenuDto;
//import com.ucarbbs.adminweb.service.meun.MenuService;
//import com.ucarbbs.adminweb.util.Constants;
//import com.ucarbbs.adminweb.util.RedisCacheUtil;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Base64;
import java.util.List;

/**
 * 
 * @author dinghao
 *
 */
@Component("adminAuthenticationSuccessHandler")
public class AdminAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    Logger successHandlerlogger = LoggerFactory.getLogger(AdminAuthenticationSuccessHandler.class);

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;

//    @Autowired
//    private MenuService menuService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {

        // token鉴权
        String header = request.getHeader("Authorization");
        if (header == null || !header.startsWith("Basic ")) {
            throw new RequestAuthorizationException(new RestFulVO(SystemRest.NOT_FIND_AUTHORIZATION));
        }
        String[] tokens = extractAndDecodeHeader(header, request);
        assert tokens.length == 2;
        String clientId = tokens[0];
        String clientSecret = tokens[1];
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
        if(clientDetails == null){
            throw new RequestAuthorizationException(new RestFulVO(SystemRest.CLIENT_ID_NOT_EXISTS));
        }
        if(!StringUtils.equals(clientDetails.getClientSecret(), clientSecret)){
            throw new RequestAuthorizationException(new RestFulVO(SystemRest.CLIENT_ID_SECRET_ERROR));
        }
        TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "");
        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
        OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
        if(StringUtils.isNotEmpty(oAuth2AccessToken.getValue())){
            successHandlerlogger.info("{}登录成功",authentication.getName());
            // TODO 1.记录登录成功日志（写库）
            // TODO 2.获取用户的所有菜单权限信息（读库）
            UserInfo user = (UserInfo)authentication.getPrincipal();

            // TODO 3.将读出来的菜单权限存储到redis中（写缓存）==>key:user_menu_info_[username] vlue：List<menu>
            //先取缓存
//            String menus = RedisCacheUtil.getValue(Constants.USER_MENU_INFO_PREFIX + user.getUserId());
//            List<MenuDto> menuList = null;
//            if(StringUtils.isEmpty(menus)){
//                menuService.clearUserMenusByUserId(user.getUserId(),false);
//            }else{
//                menuList= JSONObject.parseArray(menus,MenuDto.class);
//            }
            // TODO 4.使用oAuth2AccessToken.getValue()获取最终的token并返回给前台
            String tokenValue = oAuth2AccessToken.getValue();
            response.setContentType("application/json;charset=UTF-8");
            // TODO 5.最终返回的因该是自定义登录成功后的VO，请不要使用authentication这里只是做测试

            response.getWriter().write(objectMapper.writeValueAsString(new RestFulVO(SystemRest.LOGIN_SUCCESS,tokenValue)));
        }else{
            throw new RequestAuthorizationException(new RestFulVO(SystemRest.CREATE_TOKEN_ERROR));
        }
    }



    private String[] extractAndDecodeHeader(String header, HttpServletRequest request)
    throws IOException {

        byte[] base64Token = header.substring(6).getBytes("UTF-8");
        byte[] decoded;
        try {
            decoded = Base64.getDecoder().decode(base64Token);
        }
        catch (IllegalArgumentException e) {
            throw new BadCredentialsException(
            "Failed to decode basic authentication token");
        }

        String token = new String(decoded, "UTF-8");

        int delim = token.indexOf(":");

        if (delim == -1) {
            throw new BadCredentialsException("Invalid basic authentication token");
        }
        return new String[] { token.substring(0, delim), token.substring(delim + 1) };
    }
}